home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / WASTE 1.1 / WEDrawing.c < prev    next >
Encoding:
Text File  |  1994-11-01  |  27.4 KB  |  972 lines  |  [TEXT/MPCC]

  1. s;
  2.  
  3.     //{ do a fast binary search through the style run array }
  4.     minIndex = 0;
  5.     maxIndex = pWE->nLines;
  6.  
  7.     while (minIndex < maxIndex)
  8.     {
  9.         index = BSR(minIndex + maxIndex, 1);
  10.         if (offset >= pLines[index].lineStart) 
  11.         {
  12.             if (offset < pLines[index + 1].lineStart) 
  13.             {
  14.                 break;
  15.             }
  16.             else
  17.             {
  18.                 minIndex = index + 1;
  19.             }
  20.         }
  21.         else
  22.         {
  23.             maxIndex = index;
  24.         }
  25.     }  //{ while }
  26.  
  27.     return index;
  28. }
  29.  
  30. pascal long _WEPixelToLine(long vOffset, WEHandle hWE)
  31. {
  32.     //{ given a vertical pixel offset in local coordinates, }
  33.     //{ find the corresponding line index }
  34.  
  35.     WEPtr pWE;
  36.     LineArrayPtr pLines;
  37.     long minIndex, maxIndex, index;
  38.     
  39.     pWE = *hWE;
  40.  
  41.     //{ get a pointer to the line array }
  42.     pLines = *pWE->hLines;
  43.  
  44.     //{ do a fast binary search through the style run array }
  45.     minIndex = 0;
  46.     maxIndex = pWE->nLines;
  47.  
  48.     while (minIndex < maxIndex)
  49.     {
  50.         index = BSR(minIndex + maxIndex, 1);
  51.         if (vOffset >= pLines[index].lineOrigin) 
  52.         {
  53.             if (vOffset < pLines[index + 1].lineOrigin) 
  54.             {
  55.                 break;
  56.             }
  57.             else
  58.             {
  59.                 minIndex = index + 1;
  60.             }
  61.         }
  62.         else
  63.         {
  64.             maxIndex = index;
  65.         }
  66.     }
  67.     
  68.     return index;
  69. }
  70.  
  71. pascal long _WEOffsetToRun (long offset, WEHandle hWE)
  72. {
  73.     WEPtr pWE;
  74.     RunArrayPtr pRuns;
  75.     long minIndex, maxIndex, index;
  76.  
  77.     pWE = *hWE;
  78.  
  79.     //{ get a pointer to the style run array }
  80.     pRuns = *pWE->hRuns;
  81.  
  82.     //{ do a fast binary search through the style run array }
  83.     minIndex = 0;
  84.     maxIndex = pWE->nRuns;
  85.  
  86.     while (minIndex < maxIndex)
  87.     {
  88.         index = BSR(minIndex + maxIndex, 1);
  89.         if (offset >= pRuns[index].runStart)
  90.         { 
  91.             if (offset < pRuns[index + 1].runStart) 
  92.             {
  93.                 break;
  94.             }
  95.             else
  96.             {
  97.                 minIndex = index + 1;
  98.             }
  99.         }
  100.         else
  101.         {
  102.             maxIndex = index;
  103.         }
  104.     } //{ while }
  105.     return index;
  106. }
  107.  
  108. pascal void _WEGetIndStyle(long runIndex, WERunInfo *info, WEHandle hWE)
  109. {
  110.     WEPtr pWE;
  111.     RunArrayPeek pTheRun;
  112.  
  113.     pWE = *hWE;
  114.  
  115.     //{ get a pointer to the specified run array element }
  116.     pTheRun = (RunArrayPeek)&(*pWE->hRuns)[runIndex];
  117.  
  118.     //{ fill in the runStart and runEnd fields from the style run array }
  119.     info->runStart = pTheRun->first.runStart;
  120.     info->runEnd = pTheRun->second.runStart;
  121.  
  122.     //{ copy the style information from the appropriate entry in the style table }
  123.     info->runAttrs = (*pWE->hStyles)[pTheRun->first.styleIndex].info;
  124. }
  125.  
  126. pascal void WEGetRunInfo(long offset, WERunInfo *info, WEHandle hWE)
  127. {
  128.     _WEGetIndStyle(_WEOffsetToRun(offset, hWE), info, hWE);
  129. }
  130.  
  131. pascal Boolean _WEIsEmbeddedObject(long offset, WEObjectDescHandle *hObjectDesc,
  132.                             WEHandle hWE)
  133. {
  134.     WERunInfo runInfo;
  135.     
  136.     WEGetRunInfo(offset, &runInfo, hWE);
  137.     *hObjectDesc = (WEObjectDescHandle)(runInfo.runAttrs.runStyle.tsObject);
  138.     return (hObjectDesc != nil);
  139. }
  140.  
  141.  
  142. pascal void _WEContinuousStyleRange(long rangeStart, long rangeEnd, short *mode,
  143.         WETextStyle *ts, WEHandle hWE)
  144. {
  145.     //{ find out which style attributes are continous over the specified text range }
  146.     //{ on entry, the mode bitmap specifies which attributes are to be checked }
  147.     //{ on exit, the mode bitmap specifies the continuous attributes, also copied to ts }
  148.  
  149.     WEPtr pWE;
  150.     long bitmap;
  151.     long runIndex;
  152.     WERunInfo runInfo;
  153.     
  154.     pWE = *hWE;
  155.  
  156.     //{ get bitmap of style attributes to check (valid bits are kModeFont..kModeColor) }
  157.     bitmap = *mode & weDoAll;
  158.  
  159.     //{ get style info at the beginning of the specified range }
  160.     runIndex = _WEOffsetToRun(rangeStart, hWE);
  161.     _WEGetIndStyle(runIndex, &runInfo, hWE);
  162.  
  163.     //{ copy the specified fields to ts }
  164.     _WECopyStyle(&runInfo.runAttrs.runStyle, (WETextStyle *)ts, 0, *mode | weDoReplaceFace);
  165.  
  166.     //{ loop through style runs across the current selection range }
  167.     //{ if we determine that all specified attributes are discontinuous, we exit prematurely }
  168.     do
  169.     {
  170.         _WEGetIndStyle(runIndex, &runInfo, hWE);
  171.  
  172.         //{ determine which attributes have changed, if any }
  173.         if (BTST(bitmap, kModeFont))
  174.         { 
  175.             if (runInfo.runAttrs.runStyle.tsFont != ts->tsFont)
  176.             { 
  177.                     BCLR(bitmap, kModeFont);
  178.             }
  179.         }
  180.         if (BTST(bitmap, kModeFace))
  181.         { 
  182.             if (runInfo.runAttrs.runStyle.tsFace != ts->tsFace)
  183.             { 
  184.                 ts->tsFace = ts->tsFace & runInfo.runAttrs.runStyle.tsFace;
  185.                 if (ts->tsFace == 0)
  186.                 { 
  187.                     BCLR(bitmap, kModeFace);
  188.                 }
  189.             }
  190.         }
  191.         if (BTST(bitmap, kModeSize))
  192.         { 
  193.             if (runInfo.runAttrs.runStyle.tsSize != ts->tsSize) 
  194.             {
  195.                 BCLR(bitmap, kModeSize);
  196.             }
  197.         }
  198.         if (BTST(bitmap, kModeColor))
  199.         { 
  200.             if (!_WEBlockCmp((Ptr)&runInfo.runAttrs.runStyle.tsColor, (Ptr)&ts->tsColor, sizeof(RGBColor)))
  201.             { 
  202.                 BCLR(bitmap, kModeColor);
  203.             }
  204.         }
  205.  
  206.         runIndex = runIndex + 1;
  207.     } while ((bitmap != 0) && (runInfo.runEnd < rangeEnd));
  208.  
  209.     *mode = bitmap;
  210. }
  211.  
  212. pascal void _WESynchNullStyle(WEHandle hWE)
  213. {
  214.     //{ This routine fills the nullStyle field of the WE record with valid information }
  215.     //{ and makes sure that the null style font belongs to the keyboard script. }
  216.  
  217.     WEPtr pWE;
  218.     long runIndex;
  219. #ifndef WASTENOSYNCH
  220.     ScriptCode keyboardScript;
  221.     short fontID;
  222. #endif
  223.     WERunInfo runInfo;
  224.     
  225.     pWE = *hWE;
  226.  
  227.     //{ find the run index of the style run preceding the insertion point }
  228.     runIndex = _WEOffsetToRun(pWE->selStart - 1, hWE);
  229.  
  230.     //{ if the nullStyle record is marked as invalid, fill it with the style attributes }
  231.     //{ associated with the character preceding the insertion point, and mark it as valid }
  232.     if (!BTST(pWE->flags, weFUseNullStyle)) 
  233.     {
  234.         _WEGetIndStyle(runIndex, &runInfo, hWE);
  235.         pWE->nullStyle = runInfo.runAttrs;
  236.         BSET(pWE->flags, weFUseNullStyle);
  237.     }
  238.  
  239. #ifndef WASTENOSYNCH
  240.     //{ if only the Roman script is installed, we're finished }
  241.     if (!BTST(pWE->flags, weFNonRoman)) 
  242.     {
  243.         return;
  244.     }
  245.  
  246.     //{ *** FONT / KEYBOARD SYNCHRONIZATION *** }
  247.     //{ get the keyboard script }
  248.     keyboardScript = GetEnvirons(smKeyScript);
  249.  
  250.     //{ find out what font will be used for the next character typed }
  251.     fontID = pWE->nullStyle.runStyle.tsFont;
  252.  
  253.     //{ do nothing if the font script is the same as the keyboard script }
  254.     if (Font2Script(fontID) == keyboardScript) return; 
  255.  
  256.     //{ scan style runs starting from the insertion point backwards,}
  257.     //{ looking for the first font belonging to the keyboard script }
  258.     do
  259.     {
  260.         _WEGetIndStyle(runIndex, &runInfo, hWE);
  261.         fontID = runInfo.runAttrs.runStyle.tsFont;
  262.         if (Font2Script(fontID) == keyboardScript) break;
  263.         runIndex = runIndex - 1;
  264.     } while (runIndex>=0);
  265.     
  266.     //{ if no font was ever used for the keyboard script, default to the }
  267.     //{ application font for the script }
  268.     if (runIndex < 0) 
  269.     {
  270.         fontID = GetScript(keyboardScript, smScriptAppFond);
  271.     }
  272.     
  273.     //{ change the font in the null style record }
  274.     pWE->nullStyle.runStyle.tsFont = fontID;
  275. #endif
  276. }
  277.  
  278. pascal Boolean WEContinuousStyle (short *mode, TextStyle *ts, WEHandle hWE)
  279. {
  280.     //{ find out which style attributes are continous over the selection range }
  281.     //{ on entry, the mode bitmap specifies which attributes are to be checked }
  282.     //{ on exit, the mode bitmap specifies the continuous attributes, also copied to ts }
  283.     //{ return TRUE if all specified attributes are continuous }
  284.  
  285.     WEPtr pWE;
  286.     short oldMode;
  287.     Boolean continuousStyle;
  288.     
  289.     pWE = *hWE;
  290.  
  291.     //{ two rather different paths are taken depending on whether }
  292.     //{ the selection range is empty or not }
  293.     if (pWE->selStart == pWE->selEnd) 
  294.     {
  295.         //{ if the selection range is empty, always return TRUE and set ts }
  296.         //{ from the nullStyle record, after having validated it }
  297.         continuousStyle = true;
  298.         _WESynchNullStyle(hWE);
  299.         _WECopyStyle(&pWE->nullStyle.runStyle, (WETextStyle *)ts, 0, *mode | weDoReplaceFace);
  300.     }
  301.     else
  302.     {
  303.         //{ otherwise get the continuous style attributes over the selection range }
  304.         oldMode = *mode;
  305.         _WEContinuousStyleRange(pWE->selStart, pWE->selEnd, mode, (WETextStyle *)ts, hWE);
  306.  
  307.         //{ return TRUE if mode hasn't changed }
  308.         continuousStyle = (oldMode == *mode);
  309.     }
  310.     return continuousStyle;
  311. }
  312.  
  313. pascal void _WESegmentLoop(long firstLine, long lastLine, SegmentLoopProcPtr callback, void *callbackData,
  314.         WEHandle hWE)
  315. {
  316.     //{ For each style segment on every line in the specified range, set up }
  317.     //{ text attributes in the port and call the callback. }
  318.     //{ the WE record must be already locked }
  319.  
  320.     WEPtr pWE;
  321.     LineArrayPtr pLines;
  322.     long pText;
  323.     long lineIndex;
  324.     long runIndex, previousRunIndex;
  325.     long lineStart, lineEnd, segmentStart, segmentEnd;
  326.     JustStyleCode styleRunPosition;
  327.     WERunInfo runInfo;
  328.     Boolean saveLineLock;
  329.     Boolean saveTextLock;
  330.     QDEnvironment saveEnvironment;
  331.     
  332.     pWE = *hWE;
  333.  
  334.     //{ save the QuickDraw environment }
  335.     _WESaveQDEnvironment(pWE->port, BTST(pWE->flags, weFHasColorQD), &saveEnvironment);
  336.  
  337.     //{ make sure firstLine and lastLine are within the allowed range }
  338.     lineIndex = pWE->nLines - 1;
  339.     firstLine = _WEPinInRange(firstLine, 0, lineIndex);
  340.     lastLine = _WEPinInRange(lastLine, 0, lineIndex);
  341.  
  342.     //{ lock the line array }
  343.     saveLineLock = _WESetHandleLock((Handle)pWE->hLines, true);
  344.     pLines = *pWE->hLines;
  345.  
  346.     //{ lock the text }
  347.     saveTextLock = _WESetHandleLock(pWE->hText, true);
  348.     pText = (long)(*pWE->hText);
  349.  
  350.     //{ find the style run index corresponding to the beginning of the first line }
  351.     runIndex = _WEOffsetToRun(pLines[firstLine].lineStart, hWE);
  352.     previousRunIndex = -1;
  353.  
  354.     //{ loop thru the specified lines }
  355.     for(lineIndex = firstLine; lineIndex<=lastLine; lineIndex++)
  356.     {
  357.         //{ get line start and line end }
  358.         lineStart = pLines[lineIndex].lineStart;
  359.         lineEnd = pLines[lineIndex + 1].lineStart;
  360.  
  361.         //{ loop thru each style run on this line }
  362.         do
  363.         {
  364.             //{ get style run information for the current style run }
  365.             _WEGetIndStyle(runIndex, &runInfo, hWE);
  366.  
  367.             if (previousRunIndex != runIndex) 
  368.             {
  369.                 //{ set new text attributes }
  370.                 TextFont(runInfo.runAttrs.runStyle.tsFont);
  371.                 TextFace(runInfo.runAttrs.runStyle.tsFace);
  372.                 TextSize(runInfo.runAttrs.runStyle.tsSize);
  373.  
  374.                 //{ remember previous run index }
  375.                 previousRunIndex = runIndex;
  376.             }
  377.  
  378.             //{ determine the relative position of this style run on the line }
  379.             styleRunPosition = 0;                                        //{ onlyStyleRun }
  380.  
  381.             if (runInfo.runStart <= lineStart)
  382.             { 
  383.                 segmentStart = lineStart;
  384.             }
  385.             else
  386.             {
  387.                 styleRunPosition = styleRunPosition + 2;    //{ rightStyleRun or middleStyleRun }
  388.                 segmentStart = runInfo.runStart;
  389.             }
  390.  
  391.             if (runInfo.runEnd >= lineEnd)
  392.             {
  393.                         segmentEnd = lineEnd;
  394.             }
  395.             else
  396.             {
  397.                 styleRunPosition = styleRunPosition + 1;    //{ leftStyleRun or middleStyleRun }
  398.                 segmentEnd = runInfo.runEnd;
  399.             }
  400.  
  401.             //{ do the callback }
  402.             if ((callback)(&pLines[lineIndex], &runInfo.runAttrs, (Ptr)(pText + segmentStart),
  403.                     segmentStart, segmentEnd - segmentStart, styleRunPosition, callbackData))
  404.             {
  405.                 break;
  406.             }
  407.  
  408.             //{ advance style run index, unless this style run goes on to the next line }
  409.             if (runInfo.runEnd <= lineEnd)
  410.             { 
  411.                 runIndex = runIndex + 1;
  412.             }
  413.         } while (runInfo.runEnd < lineEnd);
  414.     }  //{ for }
  415.  
  416.     //{ unlock the text }
  417.     _WESetHandleLock((Handle)pWE->hText, saveTextLock);
  418.  
  419.     //{ unlock the line array }
  420.     _WESetHandleLock((Handle)pWE->hLines, saveLineLock);
  421.  
  422.     //{ restore the QuickDraw environment }
  423.     _WERestoreQDEnvironment(&saveEnvironment);
  424. }
  425.  
  426. pascal void _WEDrawTSMHilite(Rect *segmentRect, short tsFlags)
  427. {
  428.     //QDPtr qd;
  429.     long flags;
  430.     short underlineHeight;
  431.     RGBColor background, foreground, saveForeground;
  432.     Boolean isColorPort;
  433.     Boolean usingTrueGray;
  434.  
  435.     flags = tsFlags;
  436.     //qd = GetQDGlobals();
  437.     isColorPort = (((CGrafPtr)(qd.thePort))->portVersion < 0);
  438.     usingTrueGray = false;
  439.  
  440.     //{ by default, the pen pattern is solid }
  441.     PenPat(&qd.black);
  442.  
  443.     //{ if we're drawing in color, set the foreground color }
  444.     if (isColorPort) 
  445.     {
  446.         //{ save foreground color }
  447.         GetForeColor(&saveForeground);
  448.  
  449.         //{ by default, the foreground color is black }
  450.         foreground.red = 0;
  451.         foreground.green = 0;
  452.         foreground.blue = 0;
  453.  
  454.         //{ if we're underlining raw (unconverted) text, see if a "true gray" is available }
  455.         if (!BTST(flags, tsTSMConverted)) 
  456.         {
  457.             GetBackColor(&background);
  458.             usingTrueGray = GetGray(GetGDevice(), &background, &foreground);
  459.         } //{ if raw text }
  460.  
  461.         //{ set the foreground color }
  462.         RGBForeColor(&foreground);
  463.     } //{ if color graf port }
  464.  
  465.     //{ if we're underlining raw (unconverted) text and no true gray is available, }
  466.     //{ simulate gray with a 50% pattern }
  467.     if (!BTST(flags, tsTSMConverted)) 
  468.     {
  469.         if (usingTrueGray == false)
  470.         { 
  471.                 PenPat(&qd.gray);
  472.         }
  473.     }
  474.     //{ use a 2-pixel tall underline if text is "selected", else use a 1-pixel tall underline }
  475.     if( BTST(flags, tsTSMSelected)) 
  476.     {
  477.         underlineHeight = 2;
  478.     }
  479.     else
  480.     {
  481.         underlineHeight = 1;
  482.     }
  483.     
  484.     //{ segmentRect becomes the rectangle to paint }
  485.     InsetRect(segmentRect, 1, 0);
  486.     segmentRect->top = segmentRect->bottom - underlineHeight;
  487.  
  488.     //{ draw the underline }
  489.     PaintRect(segmentRect);
  490.  
  491.     //{ restore the foreground color }
  492.     if (isColorPort) 
  493.     {
  494.         RGBForeColor(&saveForeground);
  495.     }
  496. }
  497.  
  498. Boolean SLDraw (LinePtr pLine, WERunAttributesPtr pAttrs, Ptr pSegment,
  499.         long segmentStart, long segmentLength, JustStyleCode styleRunPosition,
  500.         void *callbackData);
  501.  
  502. // typedef BitMap *BitMapPtr; removed in 1.0
  503.  
  504. Boolean SLDraw (LinePtr pLine, WERunAttributesPtr pAttrs, Ptr pSegment,
  505.         long segmentStart, long segmentLength, JustStyleCode styleRunPosition,
  506.         void *callbackData)
  507. {
  508.     struct SLDrawData *p = (struct SLDrawData *) callbackData;
  509.     WEPtr pWE = p->pWE;
  510.     Fixed slop;
  511.     Rect segmentRect;
  512.     RGBColor theColor;
  513.     Boolean retval;
  514.     Rect drawRect;                    //{ visible portion of the line rectangle }
  515.     PixMapHandle offscreenPixels;
  516.     GrafPtr screenPort;
  517.     GDHandle screenDevice;
  518.     Rect lineRect;                    //{ rectangle enclosing the current line }
  519.  
  520.     retval = false;                            //{ keep looping }
  521.  
  522.     //{ is this the first segment on this line? }
  523.     if (styleRunPosition <= smLeftStyleRun) 
  524.     {
  525.         //{ calculate the line rectangle (the rectangle which completely encloses the current line) }
  526.         lineRect.left = pWE->destRect.left;
  527.         lineRect.right = pWE->destRect.right;
  528.         lineRect.top = pWE->destRect.top + pLine->lineOrigin;
  529.         lineRect.bottom = pWE->destRect.top + ((LinePeek)pLine)->second.lineOrigin;
  530.  
  531.         //{ calculate the visible portion of this rectangle }
  532.         //{ we do this by intersecting the line rectangle with the view rectangle }
  533.         drawRect = (*pWE->viewRgn)->rgnBBox;
  534.         if (SectRect(&lineRect, &drawRect, &drawRect))
  535.         { 
  536.             ;
  537.         }
  538.         if (p->usingOffscreen) 
  539.         {
  540.             //{ calculate the boundary rectangle for the offscreen buffer }
  541.             //{ this is simply drawRect converted to global coordinates }
  542.             p->bounds = drawRect;
  543.             LocalToGlobal((Point *)&p->bounds.top);
  544.             LocalToGlobal((Point *)&p->bounds.bottom);
  545.  
  546.             //{ update the offscreen graphics world for the new bounds (this could fail) }
  547.             p->drawingOffscreen = false;
  548.             if (UpdateGWorld((GWorldPtr *)(&pWE->offscreenPort), 0, &p->bounds, (CTabHandle)nil,
  549.                 (GDHandle)nil, (GWorldFlags)0) >= 0) 
  550.             {
  551.                 //{ NOTE: when running on a 68000 machine with the original QuickDraw, }
  552.                 //{ a GWorld is just an extended GrafPort, and GetGWorldPixMap actually }
  553.                 //{ returns a handle to a _copy_ of the GrafPort portBits (a BitMap, not a PixMap). }
  554.                 //{ An important side-effect of this is that when we call SetOrigin, }
  555.                 //{ only the original portBits is offset, not the copy. }
  556.                 //{ get the pixel map associated with the offscreen graphics world }
  557.                 offscreenPixels = GetGWorldPixMap((GWorldPtr)(pWE->offscreenPort));
  558.  
  559.                 //{ lock it down }
  560.                 if (LockPixels(offscreenPixels)) 
  561.                 {
  562.                     //{ offscreen pixel buffer allocation was successful }
  563.                     p->drawingOffscreen = true;
  564.  
  565.                     //{ switch graphics world }
  566.                     GetGWorld((GWorldPtr *)(&screenPort), &screenDevice);
  567.                     SetGWorld((GWorldPtr)(pWE->offscreenPort), nil);
  568.  
  569.                     //{ synchronize the coordinate system of the offscreen port with that of the screen port }
  570.                     SetOrigin(drawRect.left, drawRect.top);
  571.  
  572.                     //{ reset the offscreen clip region }
  573.                     ClipRect(&drawRect);
  574.                 }
  575.             } //{ if pixel buffer allocation was successful }
  576.         } //{ if usingOffscreen }
  577.  
  578.         //{ if doErase is TRUE, erase the drawable area before drawing text }
  579.         if (p->doErase) 
  580.         {
  581.             EraseRect(&drawRect);
  582.         }
  583.         //{ position the pen }
  584.         MoveTo(lineRect.left + _WECalcPenIndent(pLine->lineSlop, pWE->alignment),
  585.             lineRect.top + pLine->lineAscent);
  586.     } //{ if first segment on line }
  587.  
  588.     //{ if drawingOffscreen, switch thePort to the offscreen port }
  589.     //{ and synchronize text attributes }
  590.     if (p->drawingOffscreen) 
  591.     {
  592.         SetPort(pWE->offscreenPort);
  593.         TextFont(pAttrs->runStyle.tsFont);
  594.         TextFace(pAttrs->runStyle.tsFace);
  595.         TextSize(pAttrs->runStyle.tsSize);
  596.     } //{ if drawingOffscreen }
  597.  
  598.     //{ get horizontal coordinate of the pen before drawing the segment }
  599.     GetPen((Point *)&segmentRect.top);
  600.  
  601.     //{ set the foreground color }
  602.     if (p->usingColor)
  603.     {
  604.         RGBForeColor(&pAttrs->runStyle.tsColor);
  605.     }
  606.     
  607.     if (pAttrs->runStyle.tsObject != NULL)
  608.     {
  609.         // { EMBEDDED OBJECT}
  610.         if (_WEDrawObject((WEObjectDescHandle)(pAttrs->runStyle.tsObject))!=noErr)
  611.         {
  612.             ; // We don't know what to do with errors
  613.         }
  614.     }
  615.     else
  616.     {
  617.         // { REGULAR TEXT }
  618.     
  619.         slop = 0;
  620.  
  621.         //{ calculate the "slop" (extra space) for this text segment (justified text only) }
  622.         if (pWE->alignment == weJustify) 
  623.         {
  624.             //{ if this is the last segment on the line, strip trailing spaces }
  625.             if (!(styleRunPosition & 1))
  626.             {
  627.                 segmentLength = VisibleLength(pSegment, segmentLength);
  628.             }
  629.             //{ calculate how much extra space is to be applied to this text segment }
  630.             slop = FixMul(NPortionText(pSegment, segmentLength, styleRunPosition, 
  631.                 *(Point *)(&kOneToOneScaling), *(Point *)(&kOneToOneScaling)), pLine->lineJustAmount);
  632.  
  633.         } //{ if alignment = weJustify }
  634.  
  635.         //{ draw the segment }
  636. #ifdef WASTE_TABS
  637.         {
  638.             long    ii,
  639.                     beginChar;
  640.             Point    penPos;
  641.     
  642.             beginChar = 0;
  643.             for (ii = 0; ii < segmentLength; ii++)
  644.                 if (pSegment[ii] == '\t')
  645.                 {
  646.                     NDrawJust(pSegment + beginChar, ii - beginChar, slop, styleRunPosition,
  647.                               *(Point *)(&kOneToOneScaling),
  648.                               *(Point *)(&kOneToOneScaling));
  649.                     GetPen(&penPos);
  650.                     MoveTo((penPos.h / WASTE_TAB_SIZE + 1) * WASTE_TAB_SIZE, penPos.v);
  651.                     beginChar = ii + 1;
  652.                 }
  653.     
  654.             NDrawJust(pSegment + beginChar, segmentLength - beginChar, slop, styleRunPosition,
  655.                       *(Point *)(&kOneToOneScaling),
  656.                       *(Point *)(&kOneToOneScaling));
  657.         }
  658. #else
  659.         NDrawJust(pSegment, segmentLength, slop, styleRunPosition, *(Point *)(&kOneToOneScaling),
  660.             *(Point *)(&kOneToOneScaling));
  661. #endif
  662.     }
  663.     
  664.     //{ get horizontal coordinate of the pen after drawing the segment }
  665.     GetPen((Point *)&segmentRect.bottom);
  666.     segmentRect.bottom = lineRect.bottom;
  667.  
  668.     //{ if this segment is in the TSM area, underline it in the appropriate way }
  669.     if (BTST(pAttrs->runStyle.tsFlags, tsTSMHilite)) 
  670.     {
  671.         _WEDrawTSMHilite(&segmentRect, pAttrs->runStyle.tsFlags);
  672.     }
  673.     if (p->drawingOffscreen) 
  674.     {
  675.         if (!(styleRunPosition & 1)) 
  676.         {
  677.             //{ after drawing offscreen the last segment, }
  678.             //{ prepare to copy the offscreen buffer to video RAM }
  679.  
  680.             //{ first set the graphics world to the screen port }
  681.             SetGWorld((GWorldPtr)(screenPort), screenDevice);
  682.  
  683.             //{ before calling CopyBits, set the foreground color to black to avoid colorization (color only) }
  684.             if (p->usingColor) 
  685.             {
  686.                 theColor.red = 0;
  687.                 theColor.green = 0;
  688.                 theColor.blue = 0;
  689.                 RGBForeColor(&theColor);
  690.             }
  691.             
  692.             //{ copy the offscreen image of the [visible portion of the] line to the screen }
  693.             CopyBits(&pWE->offscreenPort->portBits, &screenPort->portBits, &drawRect,
  694.                     &drawRect, srcCopy, (RgnHandle)nil);
  695.  
  696.             //{ restore the original offscreen coordinate system and unlock the pixel image }
  697.             SetPort(pWE->offscreenPort);
  698.             SetOrigin(0, 0);
  699.             UnlockPixels(offscreenPixels);
  700.  
  701.         } //{ if last segment }
  702.  
  703.         //{ restore the screen port for _WESegmentLoop }
  704.         SetPort(screenPort);
  705.     } //{ if drawingOffscreen }
  706.     return retval;
  707. }
  708.  
  709. pascal void _WEDrawLines (long firstLine, long lastLine, Boolean doErase, WEHandle hWE)
  710. {
  711.     //{ draw the specified range of lines }
  712.     //{ we can safely assume that the WE record is already locked }
  713.     //{ and the port is already set the pWE->port }
  714.  
  715.     WEPtr pWE;
  716.     Rect bounds;                    //{ bounds of the offscreen buffer, in global coordinates }
  717.     Boolean usingColor;                //{ TRUE if we're drawing in color }
  718.     Boolean usingOffscreen;            //{ TRUE if we're using an offscreen port }
  719.     Boolean drawingOffscreen;        //{ TRUE if actually drawing to an offscreen buffer }
  720.     struct SLDrawData callbackData;
  721.  
  722.  
  723.     pWE = *hWE;
  724.     usingOffscreen = false;
  725.     drawingOffscreen = false;
  726.  
  727.     //{ do nothing if our graphics port is not visible }
  728.     if (EmptyRgn(pWE->port->visRgn))
  729.     {
  730.         return;
  731.     }
  732.  
  733.     //{ If doErase is TRUE, we're drawing over old text, so we must erase each line }
  734.     //{ before redrawing it.  But if the weFDrawOffscreen feature is enabled, we draw }
  735.     //{ the entire line offscreen and  we copy the image right over the old line, }
  736.     //{ without erasing it, thus achieving a very smooth drawing effect. }
  737.  
  738.     if ((doErase) && BTST(pWE->flags, weFDrawOffscreen)) 
  739.     {
  740.         //{ has an offscreen world already been allocated? }
  741.         if (pWE->offscreenPort == nil) 
  742.         {
  743.             //{ nope,  create one; its bounds are set initially to an arbitrary rectangle }
  744.             SetRect(&bounds, 0, 0, 1, 1);
  745.             NewGWorld((GWorldPtr *)(/*&*/pWE->offscreenPort), 0, &bounds, nil, nil,
  746.                 pixPurge + noNewDevice + useTempMem);
  747.         }
  748.         usingOffscreen = (pWE->offscreenPort != nil);
  749.     }
  750.  
  751.     usingColor = BTST(pWE->flags, weFHasColorQD);
  752.     callbackData.pWE = pWE;
  753.     callbackData.bounds = bounds;
  754.     callbackData.usingColor = usingColor;
  755.     callbackData.usingOffscreen = usingOffscreen;
  756.     callbackData.drawingOffscreen = drawingOffscreen;
  757.     callbackData.doErase = doErase;
  758.     _WESegmentLoop(firstLine, lastLine, SLDraw, (void *) &callbackData, hWE);
  759. }
  760.  
  761. pascal short _WECalcPenIndent(short slop, short alignment)
  762. {
  763.     short retval;
  764.  
  765.     //{ if alignment is weFlushDefault, use the system global SysDirection }
  766.     if (alignment == weFlushDefault) 
  767.     {
  768.         if (GetSysJust() == 0)
  769.         { 
  770.             alignment = weFlushLeft;
  771.         }
  772.         else
  773.         {
  774.             alignment = weFlushRight;
  775.         }
  776.     }
  777.     if (alignment == weFlushRight) 
  778.     {
  779.         retval = slop;                                //{ right aligned }
  780.     }
  781.     else if (alignment == weCenter) 
  782.     {
  783.         retval = slop / 2;                        //{ centered }
  784.     }
  785.     else
  786.     {
  787.         retval = 0;                                    //{ left aligned or justified }
  788.     }
  789.     return retval;
  790. }
  791.  
  792. pascal void _WESaveQDEnvironment(GrafPtr port, Boolean saveColor, QDEnvironment *theEnvironment)
  793. {
  794.     GetPort(&theEnvironment->envPort);
  795.     SetPort(port);
  796.     GetPenState(&theEnvironment->envPen);
  797.     PenNormal();
  798.     theEnvironment->envStyle.tsFont = port->txFont;
  799.     theEnvironment->envStyle.tsFace = ((GrafPtr1)port)->txFace;
  800.     theEnvironment->envStyle.tsFlags = saveColor;        //{ remember if color was saved }
  801.     theEnvironment->envStyle.tsSize = port->txSize;
  802.     if (saveColor) 
  803.     {
  804.         GetForeColor(&theEnvironment->envStyle.tsColor);
  805.     }
  806.     theEnvironment->envMode = port->txMode;
  807.     TextMode(srcOr);
  808. }
  809.  
  810. pascal void _WERestoreQDEnvironment(QDEnvironment *theEnvironment)
  811. {
  812.     SetPenState(&theEnvironment->envPen);
  813.     TextFont(theEnvironment->envStyle.tsFont);
  814.     TextFace(theEnvironment->envStyle.tsFace);
  815.     TextSize(theEnvironment->envStyle.tsSize);
  816.     TextMode(theEnvironment->envMode);
  817.     if (theEnvironment->envStyle.tsFlags) 
  818.     {
  819.         RGBForeColor(&theEnvironment->envStyle.tsColor);
  820.     }
  821.     SetPort(theEnvironment->envPort);
  822. }
  823.  
  824. pascal void _WEFillFontInfo (GrafPtr port, WERunAttributes *targetStyle)
  825. {
  826.     //{ given a WERunAttributes record, fill in the runHeight, runAscent fields etc. }
  827.     FontInfo fInfo;
  828.     QDEnvironment saveEnvironment;
  829.  
  830.     _WESaveQDEnvironment(port, false, &saveEnvironment);
  831.  
  832.     //{ we don't want a zero font size; although QuickDraw accepts zero to mean }
  833.     //{ the default font size, it can cause trouble to us when we do calculations }
  834.     if (targetStyle->runStyle.tsSize == 0) 
  835.     {
  836.         targetStyle->runStyle.tsSize = 12;
  837.     }
  838.     
  839.     //{ set the text attributes }
  840.     TextFont(targetStyle->runStyle.tsFont);
  841.     TextSize(targetStyle->runStyle.tsSize);
  842.     TextFace(targetStyle->runStyle.tsFace);
  843.     GetFontInfo(&fInfo);
  844.     targetStyle->runHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
  845.     targetStyle->runAscent = fInfo.ascent;
  846.     _WERestoreQDEnvironment(&saveEnvironment);
  847. }
  848.  
  849. pascal void _WECopyStyle(WETextStyle *sourceStyle, WETextStyle *targetStyle, short offStyles,
  850.         short mode)
  851. {
  852.     //{ Copy some or all of the attributes composing sourceStyle to targetStyle. }
  853.     //{ The mode parameter determines which attributes are to be copied and how. }
  854.     //{ If mode contains weDoToggleFace,  offStyles indicates which }
  855.     //{ QuickDraw styles are to be turned off. }
  856.  
  857.     long longMode;
  858.     long longSize;
  859.     long sourceFace, targetFace;
  860.  
  861.     longMode = mode;    //{ this allows the compiler to generate tighter code }
  862.  
  863.     //{ if the kModeFont bit is set, copy the font family number }
  864.     if (BTST(longMode, kModeFont))
  865.     { 
  866.             targetStyle->tsFont = sourceStyle->tsFont;
  867.     }
  868.     
  869.     //{ if the kModeSize or the kModeAddSize bit is set, alter the font size }
  870.     if ((longMode & (weDoSize + weDoAddSize)) != 0) 
  871.     {
  872.         longSize = sourceStyle->tsSize;
  873.  
  874.         //{ if kModeAddSize is set, the source size is added to the target size, }
  875.         //{ otherwise the source size replaces the target size outright }
  876.         if (BTST(longMode, kModeAddSize)) 
  877.         {
  878.             longSize = longSize + targetStyle->tsSize;
  879.         }
  880.         //{ range-check the resulting size }
  881.         longSize = _WEPinInRange(longSize, kMinFontSize, kMaxFontSize);
  882.         targetStyle->tsSize = longSize;
  883.     } //{ if alter size }
  884.  
  885.     //{ if kModeFace is set, copy the QuickDraw styles (tsFace field); }
  886.     //{ the (rather complex) rules for copying the styles are explained below in detail }
  887.     if (BTST(longMode, kModeFace)) 
  888.     {
  889.         sourceFace = sourceStyle->tsFace;
  890.         targetFace = targetStyle->tsFace;
  891.     
  892.         //{ sourceFace replaces targetFace outright if one or both of these conditions hold: }
  893.         //{ 1. sourceFace is zero (= empty set = plain text) }
  894.         //{ 2. the kModeReplaceFace bit is set }
  895.     
  896.         if ((sourceFace == 0) || BTST(longMode, kModeReplaceFace)) 
  897.         {
  898.             targetFace = sourceFace;
  899.         }
  900.         else
  901.         {
  902.             //{ Otherwise sourceFace is interpreted as a bitmap indicating }
  903.             //{ which styles are to be altered -- all other styles are left intact. }
  904.             //{ What exactly happens to the styles indicated in sourceFace }
  905.             //{ depends on whether the kModeToggleFace bit is set or clear. }
  906.     
  907.             //{ if kModeToggleFace is set, turn a style off if it's set in offStyles, else turn it on }
  908.             if (BTST(longMode, kModeToggleFace)) 
  909.             {
  910.                 targetFace = (sourceFace ^ offStyles) | (targetFace & (~sourceFace));
  911.             }
  912.             else
  913.             {
  914.                 //{ if kModeToggleFace is clear, turn on the styles specified in sourceStyle }
  915.                 targetFace = targetFace | sourceFace;
  916.             }
  917.             //{ the condense and extend attributes are mutually exclusive: if one is set }
  918.             //{ in sourceFace, remove it from targetFace }
  919.             if (BTST(sourceFace, tsCondense))
  920.             { 
  921.                 BCLR(targetFace, tsExtend);
  922.             }
  923.             else if (BTST(sourceFace, tsExtend)) 
  924.             {
  925.                 BCLR(targetFace, tsCondense);
  926.             }
  927.         }
  928.         targetStyle->tsFace = targetFace;
  929.     }  //{ if alter face }
  930.  
  931.     //{ if kModeColor is set, change target color }
  932.     if (BTST(longMode, kModeColor)) 
  933.     {
  934.         targetStyle->tsColor = sourceStyle->tsColor;
  935.     }
  936.     
  937.     //{ if kModeObject is set, copy object descriptor }
  938.     if (BTST(longMode, kModeObject))
  939.     {
  940.         targetStyle->tsObject = sourceStyle->tsObject;
  941.     }
  942.  
  943.     //{ always clear targetStyle.tsFlags by default }
  944.     targetStyle->tsFlags = 0;
  945.  
  946.     //{ if kModeFlags is set, copy the tsFlags field }
  947.     if (BTST(longMode, kModeFlags))
  948.     { 
  949.         targetStyle->tsFlags = sourceStyle->tsFlags;
  950.     }
  951. }
  952.  
  953. pascal Boolean _WEOffsetInRange(long offset, char edge, long rangeStart, long rangeEnd)
  954. {
  955.     //{ return TRUE if the position specified by the pair < offset, edge > }
  956.     //{ is within the specified range }
  957.  
  958.     //{ if edge is kTrailingEdge, offset really refers to the preceding character }
  959.     if (edge == kTrailingEdge) 
  960.     {
  961.         if (offset > 0) 
  962.         {
  963.             offset = offset - 1;
  964.         }
  965.     }
  966.     //{ return TRUE iff offset is within the specified range }
  967.     return ((offset >= rangeStart) && (offset < rangeEnd));
  968. }
  969.  
  970.  
  971.  
  972.